package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/henrylee2cn/goutil"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"studygo/other/picutils"
	"sync"
	"time"
)

func init() {
	log.SetPrefix("TRACE: ")
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

type picBean struct {
	name        string
	picCount    int
	firstPicUrl string
}

var (
	wg          sync.WaitGroup
	baseUrl                   = "https://www.nvshens.org/"
	picSavePath               = "d:/tmp/psnv28098_唐安琪/"
	picChan     chan *picBean = make(chan *picBean, 10)
)

func main() {
	//从命令行获取参数https://www.nvshens.org/girl/27854/  24633 27718 22162
	mainUrlCMD := flag.String("url", "https://www.nvshens.org/girl/28098/", "图片链接地址页")
	picSavePathCMD := flag.String("s", picSavePath, "下载保存位置")
	flag.Parse()
	picSavePath = picutils.PathDo(*picSavePathCMD)
	mainUrl := picutils.PathDo(*mainUrlCMD)
	startTime := time.Now()
	log.Println("下载地址和保存位置是:", mainUrl, picSavePath)

	go collectPic(mainUrl, picChan)

	downFromChan(picChan)
	wg.Wait()
	endTime := time.Now()
	log.Println("开始时间|结束时间", startTime.Format("2006-01-02 15:04:05"), endTime.Format("2006-01-02 15:04:05"))
}

//从管道中获取并下载图片
func downFromChan(picChan <-chan *picBean) {
	log.Println("下载开始~~")
	for {
		if data, ok := <-picChan; ok {
			wg.Add(1)
			go downPicByPicBeanByCmd(data)
		} else {
			break
		}
	}
	/*label:
	for {
		select {
		case v := <-picChan:
			if v != nil {
				log.Println("从管道中取出数据", v)
				downPicByPicBeanByCmd(v)
			}
		default:
			log.Println("管道取不到数据")
			break label
		}
	}
	log.Println(strings.Repeat("-", 80))
	stopChan <- true*/
}

// 收集图片到管道
func collectPic(url string, picChan chan *picBean) {
	resp, err := http.Get(url)
	if err != nil {
		log.Println(url, "访问失败")
		return
	}
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		log.Println(url, "err:", err)
		return
	}
	findLen := doc.Find(".archive_more a").Nodes
	if len(findLen) == 0 {
		//只有当前页面这部分,不用翻页	去查找
		getSinalePic(doc)
	} else {
		albumText := doc.Find(".archive_more a").First().Text()
		i, b := picutils.GetInt(albumText)
		if !b {
			getAlbumPic(url, i)
		}
	}
	close(picChan)
}

//提取图片|https://www.nvshens.org/girl/24633/
// i 表示 总 数量 比如这个是 41
func getAlbumPic(url string, count int) {
	//https://www.nvshens.org/girl/24633/album/2.html
	log.Println("是 album 类型页面 ", url)
	for i := 1; i <= (count+29)/30; i++ {
		strurl := url + "album/" + strconv.Itoa(i) + ".html"
		getAlbumDetail(url, strurl)
	}
}

//解析 https://www.nvshens.org/girl/24633/album/
func getAlbumDetail(url, albumUrl string) {
	doc, err := picutils.HttpGetByUrl(albumUrl)
	if err != nil {
		log.Println("解析album失败")
		return
	}
	doc.Find(".photo_ul .igalleryli .igalleryli_div .igalleryli_link").Each(func(i int, s *goquery.Selection) {
		attrHref, exists := s.Attr("href")
		if exists {
			parsePicByUrl(baseUrl + attrHref)
		}
	})
}

// 当前页面只有1页 ，类似于 https://www.nvshens.org/girl/27898/
func getSinalePic(doc *goquery.Document) {
	doc.Find(".photo_ul .igalleryli_div .igalleryli_link").Each(func(i int, s *goquery.Selection) {
		attr, _ := s.Attr("href")
		parsePicByUrl(baseUrl + attr)
	})
}

// 解析 图片url(https://www.nvshens.org/g/34020/)
func parsePicByUrl(url string) {
	resp, err := http.Get(url)
	if err != nil {
		log.Println("地址失败", url)
	}
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return
	}
	text := doc.Find("#dinfo span").Text()
	//第一个图片地址|https://img.onvshen.com:85/gallery/27898/34020/s/0.jpg
	var first = doc.Find("#hgallery img").First()
	firstPicURL, _ := first.Attr("src")
	pageCount, b := picutils.GetInt(text)
	if !b {
		split := strings.Split(url, "/")
		picBean := &picBean{name: split[len(split)-2] + "_" + strconv.Itoa(pageCount), picCount: pageCount, firstPicUrl: firstPicURL}
		log.Println("", picBean)
		picChan <- picBean
	}

}

func downPicByPicBeanByCmd(bean *picBean) {
	defer wg.Done()
	index := strings.LastIndex(bean.firstPicUrl, "/")
	strBaseUrl := bean.firstPicUrl[:index+1] //文件基本名字(除去最后扩展名)
	picExt := path.Ext(bean.firstPicUrl)     //文件扩展名

	picutils.MkdirFileAll(picSavePath, bean.name)
	var downPicUrl string
	for i := 0; i < bean.picCount; i++ {
		if i == 0 {
			downPicUrl = strBaseUrl + strconv.Itoa(i) + picExt
		} else {
			downPicUrl = strBaseUrl + fmt.Sprintf("%03d", i) + picExt
		}
		filepath := picSavePath + bean.name + "/" + fmt.Sprintf("%03d", i) + picExt
		if !goutil.FileExists(filepath) {
			picutils.ExecuteCmd("curl", "--connect-timeout", "10", "-m", "20", "--referer", baseUrl, downPicUrl, "-o", filepath)
		}
	}
}

//根据 图片详情下载图片
func downPicByPicBean(bean *picBean) {
	index := strings.LastIndex(bean.firstPicUrl, "/")
	strBaseUrl := bean.firstPicUrl[:index] //文件基本名字(除去最后扩展名)
	picExt := path.Ext(bean.firstPicUrl)   //文件扩展名

	picSaveFile := picSavePath + "/" + bean.name
	_, err := os.Stat(picSaveFile)
	if err != nil {
		os.MkdirAll(picSavePath+"/"+bean.name, os.ModePerm)
	}
	for i := 1; i <= bean.picCount; i++ {
		client := &http.Client{}
		url := strBaseUrl + "/" + fmt.Sprint(i) + picExt
		request, err := http.NewRequest("GET", url, nil)
		//有些网站需要加referer
		//request.Header.Add("referer", bean.firstPicUrl)
		if err != nil {
			log.Println("请求失败")
			panic(err)
		}
		//处理请求结果
		response, err := client.Do(request)
		response.Body.Close()
		all, err := ioutil.ReadAll(response.Body)
		_ = ioutil.WriteFile(picSaveFile+"/"+path.Base(url), all, 0644)
	}
	//log.Println("down finished:", bean)
}
